home *** CD-ROM | disk | FTP | other *** search
- /*
- ------------------------------------------------------------------------------
- | Sun Microsystems, TOPS Division
- | 950 Marina Village Parkway
- | P.O. Box 4016
- | Alameda, CA 94501
- |
- | Copyright (c) 1989 Sun Microsystems, Inc. All rights reserved.
- |
- | Sun considers its source code as an unpublished, proprietary trade secret,
- | and it is available only under strict license provisions. This copyright
- | notice is placed here only to protect Sun in the event the source is deemed
- | a published work. Disassembly, decompilation, or other means of reducing the
- | object code to human readable form is prohibited by the license agreement
- | under which this code is provided to the user or company in possession of
- | this copy.
- |
- | RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the Government
- | is subject to restrictions as set forth in subparagraph (c) (1) (ii) of the
- | Rights in Technical Data and Computer Software clause at DFARS 52.227-7013
- | and in similar clauses in the FAR and NASA FAR supplement.
- ------------------------------------------------------------------------------
- */
-
-
-
- /*
- ================================================================================
- **
- ** PROJECT: SoftTalk
- **
- ** FILE: STServer.c
- **
- ** Purpose:
- ** This file is an example of how to write a SoftTalk server. It demonstrates how
- ** to create a server entity, how to export your functions by registering them with
- ** SoftTalk, and how to convert SoftTalk's register-based calling conventions into
- ** standard C function calls. Furthermore, it demonstrates how to ensure that you
- ** have access to your globals when your service routines are called at interrupt-time.
- **
- ** ----------------------------------------------------------------------------
- **
- ** Version Date Author Description
- ** ------- ---- ------ -----------
- ** 1.0.2 30-Aug-89 MAC Second draft. Added Func6, SampleStruct.
- ** 1.0.1 17-Aug-89 MAC First draft.
- **
- ================================================================================
- */
-
-
-
- /*
- **------------------------------------------------------------------------------
- ** INCLUDES
- **------------------------------------------------------------------------------
- */
- #include "STServer.h"
- #include <MacTypes.h>
- #include "SoftTalk.h"
- #include "CSTServerApp.h"
- #include <pascal.h>
- #include "InterruptEnv.h"
-
-
- /*
- **------------------------------------------------------------------------------
- ** CONST
- **------------------------------------------------------------------------------
- */
- #define kFunctionRank (kSystemTaskRank)
- /* we want to be called with lower priority than at SystemTask() time */
-
-
-
- /*
- **------------------------------------------------------------------------------
- ** GLOBAL VARS
- **------------------------------------------------------------------------------
- */
- extern CSTServerApp* gApp; /* only so we can print information */
-
- static STServer gServerID = 0; /* the id of the server entity we create */
-
- static INT32 gFunc1Count = 0; /* count how many times func1() has been called */
- static INT32 gFunc2Count = 0; /* count how many times func2() has been called */
- static INT32 gFunc3Count = 0; /* count how many times func3() has been called */
- static INT32 gFunc4Count = 0; /* count how many times func4() has been called */
- static INT32 gFunc5Count = 0; /* count how many times func5() has been called */
-
-
-
-
- /*
- **------------------------------------------------------------------------------
- ** PROTOTYPES
- **------------------------------------------------------------------------------
- */
- extern pascal void NumToString(long, Str255); /* for WriteLn purposes */
- static INT32 _AcceptSession(void); /* Glue from SoftTalk/Consulair to Lightspeed */
- static INT32 _Func1(void); /* Glue from SoftTalk/Consulair to Lightspeed */
- static INT32 _Func2(void); /* Glue from SoftTalk/Consulair to Lightspeed */
- static INT32 _Func3(void); /* Glue from SoftTalk/Consulair to Lightspeed */
- static INT32 _Func4(void); /* Glue from SoftTalk/Consulair to Lightspeed */
- static INT32 _Func5(void); /* Glue from SoftTalk/Consulair to Lightspeed */
- static INT32 AcceptSession(STSession sessionID);
-
- static INT32 SetupInterruptEnv(void); /* setup interrupt-level environment */
- static void ExitInterruptEnv(INT32 value); /* clean-up from interrupt-level environment */
-
-
-
-
- /*
- ** ----------------------------------------------------------------------------
- ** FUNCTION SetupInterruptEnv() => INT32: setup interrupt-level environment
- ** ----------------------------------------------------------------------------
- **
- ** Purpose:
- ** Create an interrupt-level environment that allows access to globals.
- ** Return the value of A5 that points to our globals.
- **
- ** Usage:
- ** Call at the beginning of an interrupt-level function that wishes to
- ** access globals. The calling routine should save the value returned
- ** by SetupInterruptEnv and hand it to ExitInterruptEnv when that is called.
- **
- ** ----------------------------------------------------------------------------
- ** Version Date Author Description
- ** ------- ---- ------ -----------
- ** 01a 8/17/89 MAC First draft.
- ** ----------------------------------------------------------------------------
- */
- static INT32 SetupInterruptEnv(void) {
- return SetA5(GetMyRealA5()); /* return the desired A5 */
- }
-
-
- /*
- ** ----------------------------------------------------------------------------
- ** FUNCTION ExitInterruptEnv() : clean-up from interrupt-level environment
- ** ----------------------------------------------------------------------------
- **
- ** Purpose:
- ** restore the environment we found before we setup our interrupt-level
- ** environment. Reset A5 to its value on entry to the interrupt routine.
- **
- ** Usage:
- ** Call at the end of an interrupt-level routine that called SetupInterruptEnv().
- ** The argument "value" should be what SetupInterruptEnv returned.
- **
- ** ----------------------------------------------------------------------------
- ** Version Date Author Description
- ** ------- ---- ------ -----------
- ** 01a 8/17/89 MAC First draft.
- ** ----------------------------------------------------------------------------
- */
- static void ExitInterruptEnv(INT32 environValue){
- (void) SetA5(environValue); /* restore the A5 we found on entry */
- }
-
-
-
-
-
- /*
- ** ----------------------------------------------------------------------------
- ** FUNCTION AcceptSession() => INT32 : can we accept another session?
- ** ----------------------------------------------------------------------------
- **
- ** Purpose:
- ** Tell SoftTalk whether our server is willing to accept another client. This
- ** service routine is required for every server. Our version simply returns TRUE
- ** indicating that we can accept another client. A real server would base its decision
- ** on available server resources, etc.
- **
- ** Usage:
- ** Since SoftTalk calls service routines with args in registers, we have some asm glue
- ** to transfer args onto the stack; we then execute a standard C function call.
- ** This asm glue routine is registered with SoftTalk, and will then be called by
- ** SoftTalk (at interrupt time) whenever a new session is requested.
- **
- ** ----------------------------------------------------------------------------
- ** Version Date Author Description
- ** ------- ---- ------ -----------
- ** 01a 8/17/89 MAC First draft.
- ** ----------------------------------------------------------------------------
- */
-
- static INT32 _AcceptSession(void) {
- asm {
- move.l d0,-(sp) /* move the arg "STSession sessionID" onto the stack */
- jsr AcceptSession /* call the C function */
- add.l #4,sp /* clean up the stack */
- }
- }
-
-
- static INT32 AcceptSession(STSession sessionID) {
- Str255 msg; /* message string */
- INT32 environValue; /* interrupt environment pointer */
-
- /* we're at interrupt level */
- environValue = SetupInterruptEnv();
-
- gApp->Msg((unsigned char*)"\pAcceptSession: sessionID = ");
- NumToString((long)sessionID,msg);
- gApp->Msg(msg);
- gApp->NewLine();
-
- ExitInterruptEnv(environValue);
- return(noErr);
- }
-
-
-
-
- /*
- ** ----------------------------------------------------------------------------
- ** FUNCTION Func1() => INT32 : sample service routine
- ** ----------------------------------------------------------------------------
- **
- ** Purpose:
- ** Example of a service routine that accepts no args. The return value is the number
- ** of times this routine has been executed (saved in the global gFunc1Count).
- **
- ** Usage:
- ** Since SoftTalk calls service routines with args in registers, we have some asm glue
- ** to transfer args onto the stack; we then execute a standard C function call.
- ** This asm glue routine is registered with SoftTalk, and will then be called by
- ** SoftTalk (at interrupt time) whenever a new session is requested.
- **
- ** ----------------------------------------------------------------------------
- ** Version Date Author Description
- ** ------- ---- ------ -----------
- ** 01a 8/17/89 MAC First draft.
- ** ----------------------------------------------------------------------------
- */
-
- static INT32 _Func1(void) {
- asm {
- jsr Func1 /* call the C function */
- }
- }
-
- INT32 Func1(void) {
- INT32 environValue; /* interrupt environment pointer */
- INT32 returnValue;
-
- /* we're at interrupt level */
- environValue = SetupInterruptEnv();
-
- returnValue = gFunc1Count++;
- gApp->Msg((unsigned char*)"\p==> Function1");
- gApp->NewLine();
- gApp->NewLine();
-
- ExitInterruptEnv(environValue);
- return(returnValue);
- }
-
-
-
-
-
-
- /*
- ** ----------------------------------------------------------------------------
- ** FUNCTION Func2() => INT32 : sample service routine
- ** ----------------------------------------------------------------------------
- **
- ** Purpose:
- ** Example of a service routine that accepts one INT32 arg. The return value is the number
- ** of times this routine has been executed (saved in the global gFunc2Count).
- **
- ** Usage:
- ** Since SoftTalk calls service routines with args in registers, we have some asm glue
- ** to transfer args onto the stack; we then execute a standard C function call.
- ** This asm glue routine is registered with SoftTalk, and will then be called by
- ** SoftTalk (at interrupt time) whenever a new session is requested.
- **
- ** ----------------------------------------------------------------------------
- ** Version Date Author Description
- ** ------- ---- ------ -----------
- ** 01a 8/17/89 MAC First draft.
- ** ----------------------------------------------------------------------------
- */
-
- static INT32 _Func2(void) {
- asm {
- move.l d0,-(sp) /* move the arg "INT32 arg1" onto the stack */
- /* NOTE: since its an INT32 we do a "move.l" */
-
- jsr Func2 /* call the C function */
-
- add.l #4,sp /* clean up the stack: add sizeof(INT32) to SP */
- }
- }
-
- INT32 Func2(INT32 arg1) {
- Str255 msg; /* message string */
- INT32 environValue; /* interrupt environment pointer */
- INT32 returnValue;
-
- /* we're at interrupt level */
- environValue = SetupInterruptEnv();
-
- returnValue = gFunc2Count++;
- gApp->Msg((unsigned char*)"\p==> Function2: arg1 = ");
- NumToString((long)arg1,msg);
- gApp->Msg(msg);
- gApp->NewLine();
- gApp->NewLine();
-
- ExitInterruptEnv(environValue);
- return(returnValue);
- }
-
-
-
-
-
-
- /*
- ** ----------------------------------------------------------------------------
- ** FUNCTION Func3() => INT32 : sample service routine
- ** ----------------------------------------------------------------------------
- **
- ** Purpose:
- ** Example of a service routine that accepts two args. The return value is the number
- ** of times this routine has been executed (saved in the global gFunc3Count).
- **
- ** Usage:
- ** Since SoftTalk calls service routines with args in registers, we have some asm glue
- ** to transfer args onto the stack; we then execute a standard C function call.
- ** This asm glue routine is registered with SoftTalk, and will then be called by
- ** SoftTalk (at interrupt time) whenever a new session is requested.
- **
- ** ----------------------------------------------------------------------------
- ** Version Date Author Description
- ** ------- ---- ------ -----------
- ** 01a 8/17/89 MAC First draft.
- ** ----------------------------------------------------------------------------
- */
-
- static INT32 _Func3(void) {
- asm {
- move.w d1,-(sp) /* move the arg "INT16 arg2" onto the stack */
- /* NOTE: since its an INT16 we do a "move.w" */
-
- move.l d0,-(sp) /* move the arg "INT32 arg1" onto the stack */
- /* NOTE: since its an INT32 we do a "move.l" */
-
- jsr Func3 /* call the C function */
-
- add.l #6,sp /* clean up the stack: add sizeof(INT16) and sizeof(INT32) to SP */
- }
- }
-
- INT32 Func3(INT32 arg1, INT16 arg2) {
- Str255 msg; /* message string */
- INT32 environValue; /* interrupt environment pointer */
- INT32 returnValue;
-
- /* we're at interrupt level */
- environValue = SetupInterruptEnv();
-
- returnValue = gFunc3Count++;
- gApp->Msg((unsigned char*)"\p==> Function3: arg1 = ");
- NumToString((long)arg1,msg);
- gApp->Msg(msg);
- gApp->Msg((unsigned char*)"\p arg2 = ");
- NumToString((long)arg2,msg);
- gApp->Msg(msg);
- gApp->NewLine();
- gApp->NewLine();
-
- ExitInterruptEnv(environValue);
- return(returnValue);
- }
-
-
-
-
-
-
- /*
- ** ----------------------------------------------------------------------------
- ** FUNCTION Func4() => INT32 : sample service routine
- ** ----------------------------------------------------------------------------
- **
- ** Purpose:
- ** Example of a service routine that accepts one C-string arg. The return value is the number
- ** of times this routine has been executed (saved in the global gFunc4Count).
- **
- ** Usage:
- ** Since SoftTalk calls service routines with args in registers, we have some asm glue
- ** to transfer args onto the stack; we then execute a standard C function call.
- ** This asm glue routine is registered with SoftTalk, and will then be called by
- ** SoftTalk (at interrupt time) whenever a new session is requested.
- **
- ** ----------------------------------------------------------------------------
- ** Version Date Author Description
- ** ------- ---- ------ -----------
- ** 01a 8/17/89 MAC First draft.
- ** ----------------------------------------------------------------------------
- */
-
- static INT32 _Func4(void) {
- asm {
- move.l d0,-(sp) /* move the arg "char* cStr" onto the stack */
- /* NOTE: since its an INT32 we do a "move.l" */
-
- jsr Func4 /* call the C function */
-
- add.l #4,sp /* clean up the stack: add sizeof(char *) to SP */
- }
- }
-
- INT32 Func4(char* cStr) {
- INT32 environValue; /* interrupt environment pointer */
- INT32 returnValue;
-
- /* we're at interrupt level */
- environValue = SetupInterruptEnv();
-
- returnValue = gFunc4Count++;
- gApp->Msg((unsigned char*)"\p==> Function4: cStr = ");
- gApp->Msg((unsigned char*)CtoPstr(cStr));
- gApp->NewLine();
- gApp->NewLine();
-
- ExitInterruptEnv(environValue);
- return(returnValue);
- }
-
-
-
-
-
-
- /*
- ** ----------------------------------------------------------------------------
- ** FUNCTION Func5() => INT32 : sample service routine
- ** ----------------------------------------------------------------------------
- **
- ** Purpose:
- ** Example of a service routine that accepts one P-string arg. The return value is the number
- ** of times this routine has been executed (saved in the global gFunc5Count).
- **
- ** Usage:
- ** Since SoftTalk calls service routines with args in registers, we have some asm glue
- ** to transfer args onto the stack; we then execute a standard C function call.
- ** This asm glue routine is registered with SoftTalk, and will then be called by
- ** SoftTalk (at interrupt time) whenever a new session is requested.
- **
- ** ----------------------------------------------------------------------------
- ** Version Date Author Description
- ** ------- ---- ------ -----------
- ** 01a 8/17/89 MAC First draft.
- ** ----------------------------------------------------------------------------
- */
-
- static INT32 _Func5(void) {
- asm {
- move.l d0,-(sp) /* move the arg "Str255 pStr" onto the stack */
- /* NOTE: since its an INT32 we do a "move.l" */
-
- jsr Func5 /* call the C function */
-
- add.l #4,sp /* clean up the stack: add sizeof(INT32) to SP */
- }
- }
-
- INT32 Func5(Str255 pStr) {
- Str255 msg; /* message string */
- INT32 environValue; /* interrupt environment pointer */
- INT32 returnValue;
-
- /* we're at interrupt level */
- environValue = SetupInterruptEnv();
-
- returnValue = gFunc5Count++;
- gApp->Msg((unsigned char*)"\p==> Function5: pStr = ");
- gApp->Msg(pStr);
- gApp->NewLine();
- gApp->NewLine();
-
- ExitInterruptEnv(environValue);
- return(returnValue);
- }
-
-
-
-
-
- /*
- ** ----------------------------------------------------------------------------
- ** FUNCTION STServerCreate() => void : create our server entity
- ** ----------------------------------------------------------------------------
- **
- ** Purpose:
- ** Creates a SoftTalk server entity by: initializing SoftTalk; opening a server,
- ** giving the server a name using STAlias(); registering the service routines using
- ** STRegister().
- **
- ** Usage:
- ** Call in order to create a server entity.
- **
- ** ----------------------------------------------------------------------------
- ** Version Date Author Description
- ** ------- ---- ------ -----------
- ** 01a 8/17/89 MAC First draft.
- ** ----------------------------------------------------------------------------
- */
-
- void STServerCreate(void) {
- STServer myServer; /* SoftTalk "magic cookie" for the server */
- STResult err; /* result code */
- Str255 msg; /* message string */
- BYTE* serverName; /* string with my server's name */
- BYTE* format; /* format string for registering functions */
-
-
- /* first stash my A5 into my code space so I can set up an interrupt environment */
- SetMyRealA5();
-
- /* initialize SoftTalk */
- err = STInitialize();
- if (err != noErr) {
- SysBeep(1);
- gApp->Msg((unsigned char*)"\pCould not initialize SoftTalk. :-(");
- return;
- }
- gApp->Msg((unsigned char*)"\pSuccessfully initialized SoftTalk! :-)");
-
-
- /* open a server */
- err = STOpenServer(&myServer, 0);
- gApp->Msg((unsigned char*)"\pTried to open server. Error Code: ");
- NumToString(err,msg);
- gApp->Msg(msg);
- if (err < noErr) {
- SysBeep(1);
- gApp->Msg((unsigned char*)"\pCould not open server :-(.");
- gApp->NewLine();
- return;
- }
- gServerID = myServer;
- gApp->Msg((unsigned char*)"\pSuccessfully opened server :-)! ServerID is:");
- NumToString((long)myServer,msg);
- gApp->Msg(msg);
- gApp->NewLine();
-
-
- /* alias the server */
- serverName = (BYTE*)"\pMichael:Dude@*";
- err = STAlias(myServer,serverName);
- gApp->Msg((unsigned char*)"\pTried to alias server. Error Code: ");
- NumToString(err,msg);
- gApp->Msg(msg);
- if (err < noErr) {
- SysBeep(1);
- gApp->Msg((unsigned char*)"\pCould not alias server :-(.");
- gApp->NewLine();
- return;
- }
- gApp->Msg((unsigned char*)"\pSuccessfully aliased server :-)!");
- gApp->NewLine();
-
-
-
- /* register the server's routines */
- format = (BYTE*)"\pI";
- err = STRegister(myServer,kAcceptSessionCode, _AcceptSession, kSystemTaskRank, format);
- gApp->Msg((unsigned char*)"\pTried to register AcceptSession(). Error Code: ");
- NumToString(err,msg);
- gApp->Msg(msg);
- if (err < noErr) {
- SysBeep(1);
- gApp->Msg((unsigned char*)"\pCould not register :-(.");
- gApp->NewLine();
- return;
- }
-
-
- format = (BYTE*)"";
- err = STRegister(myServer,(UINT32)'F1', _Func1, kFunctionRank, format);
- gApp->Msg((unsigned char*)"\pTried to register Function1(). Error Code: ");
- NumToString(err,msg);
- gApp->Msg(msg);
- if (err < noErr) {
- SysBeep(1);
- gApp->Msg((unsigned char*)"\pCould not register :-(.");
- gApp->NewLine();
- return;
- }
-
- format = (BYTE*)"4";
- err = STRegister(myServer,(UINT32)'F2', _Func2, kFunctionRank, format);
- gApp->Msg((unsigned char*)"\pTried to register Function2(). Error Code: ");
- NumToString(err,msg);
- gApp->Msg(msg);
- if (err < noErr) {
- SysBeep(1);
- gApp->Msg((unsigned char*)"\pCould not register :-(.");
- gApp->NewLine();
- return;
- }
-
- format = (BYTE*)"42";
- err = STRegister(myServer,(UINT32)'F3', _Func3, kFunctionRank, format);
- gApp->Msg((unsigned char*)"\pTried to register Function3(). Error Code: ");
- NumToString(err,msg);
- gApp->Msg(msg);
- if (err < noErr) {
- SysBeep(1);
- gApp->Msg((unsigned char*)"\pCould not register :-(.");
- gApp->NewLine();
- return;
- }
-
- format = (BYTE*)"C";
- err = STRegister(myServer,(UINT32)'F4', _Func4, kFunctionRank, format);
- gApp->Msg((unsigned char*)"\pTried to register Function4(). Error Code: ");
- NumToString(err,msg);
- gApp->Msg(msg);
- if (err < noErr) {
- SysBeep(1);
- gApp->Msg((unsigned char*)"\pCould not register :-(.");
- gApp->NewLine();
- return;
- }
-
- format = (BYTE*)"P";
- err = STRegister(myServer,(UINT32)'F5', _Func5, kFunctionRank, format);
- gApp->Msg((unsigned char*)"\pTried to register Function5(). Error Code: ");
- NumToString(err,msg);
- gApp->Msg(msg);
- if (err < noErr) {
- SysBeep(1);
- gApp->Msg((unsigned char*)"\pCould not register :-(.");
- gApp->NewLine();
- return;
- }
-
- gApp->Msg((unsigned char*)"\pSuccessfully registered service routines :-)!");
- gApp->NewLine();
- }
-
-
-
-
-
-
-
-
- /*
- ** ----------------------------------------------------------------------------
- ** FUNCTION STServerDispose() => void : close down the server entity
- ** ----------------------------------------------------------------------------
- **
- ** Purpose:
- ** Close down a server that has been previously created.
- **
- ** Usage:
- ** After you're done with the server, simply call this routine to close down the
- ** connection to SoftTalk.
- **
- ** ----------------------------------------------------------------------------
- ** Version Date Author Description
- ** ------- ---- ------ -----------
- ** 01a 8/17/89 MAC First draft.
- ** ----------------------------------------------------------------------------
- */
-
- void STServerDispose(void) {
- STResult err; /* result code */
- Str255 msg; /* message string */
-
- /* close the server */
- err = STCloseServer(gServerID);
- gApp->Msg((unsigned char*)"\pDispose: Tried to close server. Error Code =");
- NumToString(err,msg);
- gApp->Msg(msg);
- if (err < noErr) {
- SysBeep(1);
- gApp->Msg((unsigned char*)"\pDispose: Could not close server :-(. Error Code =");
- gApp->NewLine();
- return;
- }
- gApp->Msg((unsigned char*)"\pDispose: Successfully closed server :-)!");
- gApp->NewLine();
- gServerID = 0;
- }
-
-
-
-
-
-
-
-
- /*
- ** ----------------------------------------------------------------------------
- ** FUNCTION STServerTrigger() => void : tell SoftTalk if we're ready to accept calls
- ** ----------------------------------------------------------------------------
- **
- ** Purpose:
- ** This routine should be called as often as possible from the outside, so that the
- ** server has a chance to tell SoftTalk when it is able to accept calls to its service
- ** routines. Currently the mechanism that SoftTalk provides for this purpose, STHear(),
- ** is not sophisticated enough to allow for accurate server control.
- **
- ** Usage:
- ** Call from the main-event-loop on every pass.
- **
- ** ----------------------------------------------------------------------------
- ** Version Date Author Description
- ** ------- ---- ------ -----------
- ** 01a 8/17/89 MAC First draft.
- ** ----------------------------------------------------------------------------
- */
-
- void STServerTrigger(void) {
- STResult result;
-
- /* if our server has been initialized, then continously call STHear() until all
- pending requests have been serviced. We call with kFunctionRank that all
- routines with priority higher or equal to this will be serviced */
- if (gServerID != 0) {
- while ( (BOOLEAN)STHear(gServerID, kFunctionRank) )
- ;
- }
- }
-